Skip to content

Build course category landing pages with sub categories - #307

Open
Idahjnr007 wants to merge 6 commits into
Hamplard-Hub:mainfrom
Idahjnr007:Build-Course-Category-Landing-Pages-with-Sub-Categories
Open

Build course category landing pages with sub categories#307
Idahjnr007 wants to merge 6 commits into
Hamplard-Hub:mainfrom
Idahjnr007:Build-Course-Category-Landing-Pages-with-Sub-Categories

Conversation

@Idahjnr007

Copy link
Copy Markdown
Contributor

Closes #190
Build course category landing pages with sub categories

CategoryHero.tsx — two changes:

Removed the gradient field from CategoryMeta and switched the section background from pastel gradients to bg-[#26215C] (the brand purple matching the Header). Text flipped to white/white-tinted accordingly.
Added catering to CATEGORY_META so it matches what the Header already had as a static entry.
categories/[slug]/page.tsx — full rebuild from Server Component → 'use client':

The previous version was a Server Component, which meant FilterSidebar (a client component with close/open drawer state) couldn't be composed into it.
URL params are now read via useSearchParams() and written via router.replace() — same pattern as
page.tsx
.
FilterSidebar is mounted with its category prop locked to the current category, so the category filter column in the sidebar reflects where you are but you can still filter by level, price, rating, and duration.
Subcategory pills are derived client-side from fetched course titles after load, so they're always accurate to real data.
Full filter chain: subcategory keyword → level → price → rating → duration → sort, all composed client-side with useMemo.
Loading state shows skeleton pill placeholders and CourseCardSkeleton grid.
Grid breakpoints: grid-cols-2 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4.
Header.tsx — mega-menu populated from API:

Removed the hardcoded CATEGORIES array.
Added a useEffect that calls coursesApi.getCategories() on mount and maps the result to { name, slug, description, icon } using getCategoryMeta for the description/icon.
Falls back to STATIC_CATEGORIES (derived from CATEGORY_META) if the API call fails — so the menu is never empty.
All category links now point to /categories/[slug] instead of /search?category=....
Desktop mega-menu items show the emoji icon next to the name, with a "Browse all courses →" footer link.
Mobile drawer items show the emoji icon inline.

Closes #190

Added Autoplay Next Lecture Toggle in Video Player.

Implemented an autoplay next lecture toggle in the video player so students can choose whether the next lecture starts automatically after the current one ends.

📋 Requirements

Added an "Autoplay" toggle switch in VideoControls.tsx
Default: on
Persist preference in localStorage per user
When lecture ends and autoplay is on: 5-second countdown overlay showing "Next: [lecture title]", then auto-navigate
Cancel button during countdown cancels autoplay
When autoplay is off: show "Next lecture" button on video end
Added Video Playback Quality Selector

Built a video playback quality selector so students on slower connections can reduce video quality to prevent buffering.

📋 Requirements

Add quality selector button to VideoControls.tsx: Auto, 1080p, 720p, 480p, 360p
When a quality is selected, switch the video src to the matching resolution URL
Maintain current playback position when switching quality
Show current quality label in button when not Auto
"Auto" uses the browser's adaptive bitrate streaming
🔧 Technical Scope

HTML5 video src switching
src/components/learn/VideoControls.tsx
📂 Affected Path

src/components/learn/VideoControls.tsx
Build Course Category Landing Page

CATEGORY_META — a lookup table mapping slugs to display name, emoji icon, tailored description, and a gradient pair. Covers all 10 existing Hamplard categories plus common extras.
getCategoryMeta(slug) — exported helper that falls back to a generated name for any unknown slug so the page degrades gracefully instead of crashing.
CategoryHero — renders the hero section: emoji icon bubble, h1, description, and a course-count pill badge. Gradient background comes from the category meta.
CategorySortSelect.tsx

Thin 'use client' component wrapping a <select> that calls router.push on change, keeping the page itself a pure Server Component.
src/app/categories/[slug]/page.tsx

generateStaticParams — fetches live categories from the API and falls back to CATEGORY_META keys if the API is unavailable during build.
generateMetadata — sets <title> and <description> per category.
Server-side data fetch with coursesApi.list({ category, limit: 100 }).
notFound() for slugs that are neither in CATEGORY_META nor have any API courses.
Subcategory pills — derived automatically from high-frequency words in course titles, rendered as <Link> pills that append ?sub=... to the URL (no JS needed).
Sort — ?sort=popular|rated|newest applied server-side to the fetched array.
Course grid — grid-cols-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 matching the exact breakpoint spec.
Instructor spotlight — top 3 instructors ranked by course count then total enrollments, showing avatar/initials, bio, stats, and avg rating.
Related categories row — horizontally scrollable on mobile, 6-column grid on desktop, links to sibling category pages.

Closes Hamplard-Hub#168
 Build Course Category Landing Pages with Sub-Categories

 CategoryHero.tsx — two changes:

Removed the gradient field from CategoryMeta and switched the section background from pastel gradients to bg-[#26215C] (the brand purple matching the Header). Text flipped to white/white-tinted accordingly.
Added catering to CATEGORY_META so it matches what the Header already had as a static entry.
categories/[slug]/page.tsx — full rebuild from Server Component → 'use client':

The previous version was a Server Component, which meant FilterSidebar (a client component with close/open drawer state) couldn't be composed into it.
URL params are now read via useSearchParams() and written via router.replace() — same pattern as
page.tsx
.
FilterSidebar is mounted with its category prop locked to the current category, so the category filter column in the sidebar reflects where you are but you can still filter by level, price, rating, and duration.
Subcategory pills are derived client-side from fetched course titles after load, so they're always accurate to real data.
Full filter chain: subcategory keyword → level → price → rating → duration → sort, all composed client-side with useMemo.
Loading state shows skeleton pill placeholders and CourseCardSkeleton grid.
Grid breakpoints: grid-cols-2 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4.
Header.tsx — mega-menu populated from API:

Removed the hardcoded CATEGORIES array.
Added a useEffect that calls coursesApi.getCategories() on mount and maps the result to { name, slug, description, icon } using getCategoryMeta for the description/icon.
Falls back to STATIC_CATEGORIES (derived from CATEGORY_META) if the API call fails — so the menu is never empty.
All category links now point to /categories/[slug] instead of /search?category=....
Desktop mega-menu items show the emoji icon next to the name, with a "Browse all courses →" footer link.
Mobile drawer items show the emoji icon inline.

Closes Hamplard-Hub#190
@drips-wave

drips-wave Bot commented Aug 27, 2026

Copy link
Copy Markdown

@Idahjnr007 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Frontend] Page: Build Course Category Landing Pages with Sub-Categories

1 participant